package com.yshebkb.sulp.handler;

import com.google.common.base.Throwables;
import com.yshebkb.sulp.domain.RestResponse;
import com.yshebkb.sulp.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 *
 * @author yshebkb
 * @date 2018/9/3
 */
@Slf4j
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class RestResponseHandler implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        final String returnTypeName = returnType.getParameterType().getName();
        return !RestResponse.class.getName().equals(returnTypeName)
                && !ResponseEntity.class.getName().equals(returnTypeName);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        final String returnTypeName = returnType.getParameterType().getName();
        String noreturn = "void";
        if (noreturn.equals(returnTypeName)) {
            return RestResponse.success(null);
        }
        if (!selectedContentType.includes(MediaType.APPLICATION_JSON)
                || RestResponse.class.getName().equals(returnTypeName)) {
            return body;
        }
        return RestResponse.success(body);
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({AppException.class})
    public <T> RestResponse<T> handleException(AppException e) {
        log.error(Throwables.getStackTraceAsString(e));
        return RestResponse.failed(e.getErrorCode(), e.getErrorMsg());
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({Throwable.class})
    public <T> RestResponse<T> handleException(Throwable e) {
        log.error(e.getLocalizedMessage());
        return RestResponse.failed(null, Throwables.getStackTraceAsString(e));
    }
}
